package com.apex.shared.core.utils;

import jakarta.servlet.http.HttpServletRequest;
import jakarta.servlet.http.HttpServletResponse;
import jakarta.servlet.http.HttpSession;
import lombok.extern.slf4j.Slf4j;
import org.springframework.aop.framework.AopContext;
import org.springframework.beans.BeansException;
import org.springframework.beans.factory.DisposableBean;
import org.springframework.beans.factory.NoSuchBeanDefinitionException;
import org.springframework.beans.factory.config.BeanFactoryPostProcessor;
import org.springframework.beans.factory.config.ConfigurableListableBeanFactory;
import org.springframework.context.ApplicationContext;
import org.springframework.context.ApplicationContextAware;
import org.springframework.context.ApplicationEvent;
import org.springframework.context.annotation.Lazy;
import org.springframework.core.env.Environment;
import org.springframework.lang.NonNull;
import org.springframework.stereotype.Component;
import org.springframework.web.context.request.RequestContextHolder;
import org.springframework.web.context.request.ServletRequestAttributes;

import java.util.Map;
import java.util.concurrent.ConcurrentHashMap;

/**
 * Spring 工具类，用于在非 Spring 管理的类中获取 Spring 容器中的 Bean
 * 提供了更多实用的功能，如获取代理对象、判断Bean是否存在等
 *
 * @author MoNaiHui
 */
@Slf4j
@Component
@Lazy(false)
public class SpringUtils implements BeanFactoryPostProcessor, ApplicationContextAware, DisposableBean {

    private static ConfigurableListableBeanFactory beanFactory;
    private static ApplicationContext applicationContext;
    private static final Map<String, Object> CACHE_MAP = new ConcurrentHashMap<>();

    @Override
    public void postProcessBeanFactory(@NonNull ConfigurableListableBeanFactory beanFactory) throws BeansException {
        SpringUtils.beanFactory = beanFactory;
    }

    @Override
    public void setApplicationContext(@NonNull ApplicationContext applicationContext) throws BeansException {
        SpringUtils.applicationContext = applicationContext;
    }

    /**
     * 获取对象，优先从缓存中获取
     */
    @SuppressWarnings("unchecked")
    public static <T> T getBean(String name) {
        return (T) CACHE_MAP.computeIfAbsent(name, k -> getBean(k, Object.class));
    }

    /**
     * 获取默认指定类型对象
     */
    public static <T> T getBean(Class<T> clazz) {
        return applicationContext.getBean(clazz);
    }

    /**
     * 获取指定名称和指定类型对象
     */
    public static <T> T getBean(String name, Class<T> clazz) {
        return applicationContext.getBean(name, clazz);
    }

    /**
     * 获取当前的代理对象
     */
    @SuppressWarnings("unchecked")
    public static <T> T getAopProxy() {
        return (T) AopContext.currentProxy();
    }

    /**
     * 获取指定类型的所有Bean
     */
    public static <T> Map<String, T> getBeansOfType(Class<T> type) {
        return applicationContext.getBeansOfType(type);
    }

    /**
     * 判断Bean是否存在
     */
    public static boolean containsBean(String name) {
        try {
            return beanFactory.containsBean(name);
        } catch (Exception e) {
            log.error("判断Bean是否存在时发生错误", e);
            return false;
        }
    }

    /**
     * 判断Bean是否为单例
     */
    public static boolean isSingleton(String name) throws NoSuchBeanDefinitionException {
        return beanFactory.isSingleton(name);
    }

    /**
     * 获取Bean的类型
     */
    public static Class<?> getType(String name) throws NoSuchBeanDefinitionException {
        return beanFactory.getType(name);
    }

    /**
     * 获取配置文件配置项的值
     */
    public static String getProperty(String key) {
        try {
            return applicationContext.getEnvironment().getProperty(key);
        } catch (Exception e) {
            log.error("获取配置项时发生错误, key: {}", key, e);
            return null;
        }
    }

    /**
     * 获取配置文件配置项的值，带默认值
     */
    public static String getProperty(String key, String defaultValue) {
        try {
            String value = getProperty(key);
            return value != null ? value : defaultValue;
        } catch (Exception e) {
            log.error("获取配置项时发生错误, key: {}", key, e);
            return defaultValue;
        }
    }

    /**
     * 获取配置文件配置项的值，自动转型
     */
    public static <T> T getProperty(String key, Class<T> targetType) {
        try {
            return applicationContext.getEnvironment().getProperty(key, targetType);
        } catch (Exception e) {
            log.error("获取配置项时发生错误, key: {}", key, e);
            return null;
        }
    }

    /**
     * 获取配置文件配置项的值，自动转型，带默认值
     */
    public static <T> T getProperty(String key, Class<T> targetType, T defaultValue) {
        try {
            T value = getProperty(key, targetType);
            return value != null ? value : defaultValue;
        } catch (Exception e) {
            log.error("获取配置项时发生错误, key: {}", key, e);
            return defaultValue;
        }
    }

    /**
     * 获取当前环境
     */
    public static String[] getActiveProfiles() {
        try {
            return applicationContext.getEnvironment().getActiveProfiles();
        } catch (Exception e) {
            log.error("获取当前环境配置时发生错误", e);
            return new String[0];
        }
    }

    /**
     * 获取当前的环境对象
     */
    public static Environment getEnvironment() {
        return applicationContext.getEnvironment();
    }

    /**
     * 获取当前的 HttpServletRequest
     */
    public static HttpServletRequest getRequest() {
        try {
            ServletRequestAttributes attributes = (ServletRequestAttributes) RequestContextHolder.getRequestAttributes();
            return attributes != null ? attributes.getRequest() : null;
        } catch (Exception e) {
            log.error("获取HttpServletRequest时发生错误", e);
            return null;
        }
    }

    /**
     * 获取当前的 HttpServletResponse
     */
    public static HttpServletResponse getResponse() {
        try {
            ServletRequestAttributes attributes = (ServletRequestAttributes) RequestContextHolder.getRequestAttributes();
            return attributes != null ? attributes.getResponse() : null;
        } catch (Exception e) {
            log.error("获取HttpServletResponse时发生错误", e);
            return null;
        }
    }

    /**
     * 获取当前的 HttpSession
     */
    public static HttpSession getSession() {
        try {
            HttpServletRequest request = getRequest();
            return request != null ? request.getSession() : null;
        } catch (Exception e) {
            log.error("获取HttpSession时发生错误", e);
            return null;
        }
    }

    /**
     * 发布事件
     */
    public static void publishEvent(ApplicationEvent event) {
        if (applicationContext != null && event != null) {
            try {
                applicationContext.publishEvent(event);
            } catch (Exception e) {
                log.error("发布事件时发生错误", e);
            }
        }
    }

    /**
     * 判断指定的 Profile 是否激活
     */
    public static boolean isProfileActive(String profile) {
        try {
            return applicationContext.getEnvironment()
                    .acceptsProfiles(org.springframework.core.env.Profiles.of(profile));
        } catch (Exception e) {
            log.error("判断Profile是否激活时发生错误", e);
            return false;
        }
    }

    /**
     * 获取当前项目的根路径
     */
    public static String getProjectPath() {
        return System.getProperty("user.dir");
    }

    /**
     * 获取当前项目的名称
     */
    public static String getApplicationName() {
        return getProperty("spring.application.name", "apex-application");
    }

    /**
     * 清除缓存和上下文
     */
    public static void clearAll() {
        clearHolder();
        CACHE_MAP.clear();
    }

    /**
     * 清除 ApplicationContext 为 Null
     */
    public static void clearHolder() {
        applicationContext = null;
        beanFactory = null;
    }

    /**
     * 实现 DisposableBean 接口, 在 Context 关闭时清理静态变量
     */
    @Override
    public void destroy() {
        clearAll();
    }
} 